package jrain.fw.core.service.support;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import jrain.fw.core.log.Logger;
import jrain.fw.core.log.LoggerFactory;
import jrain.fw.core.service.DestroyService;
import jrain.fw.core.service.InitService;
import jrain.fw.core.service.Service;
import jrain.fw.core.service.ServiceCfg;
import jrain.fw.core.service.ServiceConst;
import jrain.fw.core.service.ctx.CtxService;
import jrain.fw.core.utils.FwUtils;
import jrain.utils.cls.ClassUtils;
import jrain.utils.collection.CollectionUtils;
import jrain.utils.collection.RMap;
import jrain.utils.consts.BaseConst;
import jrain.utils.exception.ServiceException;
import jrain.utils.lang.StringUtils;

/**
 * <pre>
 * 作者：3244924214@qq.com
 * 描述：注解扫描服务
 * </pre>
 */
public class ClasspathAnnotationServiceContext implements CtxService {

	private static final Map<String, Object> serviceMap = new HashMap<String, Object>();
	private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
	private static final AtomicBoolean init = new AtomicBoolean(false);
	private static final List<String> initializeds = new ArrayList<>();
	private static final Logger log = LoggerFactory.getLogger("ctx-service");

	public ClasspathAnnotationServiceContext() {
		init();
	}

	@Override
	public void putService(String key, Object service) {
		lock.writeLock().lock();
		try {
			serviceMap.put(key, service);
		} finally {
			lock.writeLock().unlock();
		}
	}

	@Override

	public Object getService(String key) {
		lock.readLock().lock();
		try {
			return serviceMap.get(key);
		} finally {
			lock.readLock().unlock();
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public <T> T getService(String key, Class<T> claz) {
		return (T) getService(key);
	}

	@Override
	public void init() {
		if (!init.getAndSet(true)) {
			RMap<String, Object> cfg = FwUtils.getFwCfg();
			// 执行初始化逻辑
			String pkgs = StringUtils.trimNull(cfg.get(ServiceCfg.serviceScan.getName()), ServiceCfg.serviceScan.getValue());
			List<String> pkgList = CollectionUtils.valueOfList(pkgs);
			for (String pkg : pkgList) {
				Set<Class<?>> set = ClassUtils.getClasses(pkg);
				Map<String, Service> tempServiceMap = new HashMap<>();
				Map<String, Class<?>> tempClassMap = new HashMap<>();
				List<String> groupNames = new ArrayList<>();
				for (Class<?> cls : set) {
					Service service = cls.getAnnotation(Service.class);
					if (service != null) {
						String serviceName = StringUtils.trimNull(service.name());
						String groupName = StringUtils.trimNull(service.group());
						String key = groupName + "-" + serviceName;
						tempServiceMap.put(key, service);
						tempClassMap.put(key, cls);
						groupNames.add(groupName);
					}
				}
				// 加载配置服务
				initService(tempServiceMap, tempClassMap, ServiceConst.S_CFG_SERVICE, initializeds);
				// 加载其他服务
				for (String groupName : groupNames) {
					initService(tempServiceMap, tempClassMap, groupName, initializeds);
				}
			}
			log.info("server started!");
		}
	}

	@Override
	public void destroy() {
		if (init.get()) {
			// 执行销毁逻辑
			for (int i = initializeds.size() - 1; i >= 0; i--) {
				String service = initializeds.get(i);
				try {
					Object obj = serviceMap.get(service);
					if (obj != null && obj instanceof DestroyService) {
						((DestroyService) obj).destroy();
					}
				} catch (Throwable t) {
					String msg = service + " stop error!";
					log.info(msg, t);
					throw new ServiceException(msg, t);
				}
			}
			log.info("server stoped!");
		}
	}

	protected void initService(Map<String, Service> serviceMap, Map<String, Class<?>> classMap, String groupName, List<String> init) {
		if (!initializeds.contains(groupName)) {
			String serviceName = StringUtils.trimNull(FwUtils.getFwCfg().get(groupName), BaseConst.DEFAULT_VALUE);
			String key = groupName + "-" + serviceName;
			Service service = serviceMap.get(key);
			if (service != null) {
				List<String> list = CollectionUtils.valueOfList(service.dependency());
				for (String sv : list) {
					initService(serviceMap, classMap, sv, init);
				}
				Class<?> cls = classMap.get(key);
				try {
					Object object = cls.newInstance();
					if (object instanceof InitService) {
						InitService initService = (InitService) object;
						initService.init();
					}
					putService(groupName, object);
				} catch (Throwable t) {
					throw new ServiceException("Service initialization exception! class=" + cls.getName(), t);
				}
				init.add(groupName);
			} else {
				throw new ServiceException("The service was not found! groupName=" + groupName);
			}
		}
	}

}
